package com.mycase.im.boot.security;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mycase.im.boot.entity.database.ImCircle;
import com.mycase.im.boot.entity.database.ImUser;
import com.mycase.im.boot.service.CircleService;
import com.mycase.im.boot.service.UserService;
import com.mycase.im.boot.entity.communication.ResponseMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.stereotype.Component;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

/**
 * 自定义用户名密码身份认证过滤器
 * @Author ZhuHJay
 * @Date 2021/8/13 15:05
 */
@Component
@Slf4j
public class CustomUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

    @Autowired
    private UserService userService;
    @Autowired
    private CircleService circleService;

    private ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        log.warn("自定义用户名密码身份认证过滤器 尝试身份认证");
        return super.attemptAuthentication(request, response);
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        log.warn("自定义用户名密码身份认证过滤器 过滤器");
        super.doFilter(request, response, chain);
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
        log.warn("自定义用户名密码身份认证过滤器 登陆成功处理器开始");
        // 获取从 CustomUserDetailsServiceImpl 中存储的用户信息
        String username = ((User) authResult.getPrincipal()).getUsername();

        ImUser user = userService.getOne(new QueryWrapper<ImUser>()
                .eq("account", username)
                // 密码字段进行排除
                .select(ImUser.class, bean -> !"password".equals(bean.getColumn())));
        // 获取该用户的动态
        List<ImCircle> dynamics = circleService.findDynamicListByUserId(user);
        responseWrite( response, ResponseMessage.success()
                .appendData("dynamics", dynamics)
                .appendData("userInfo", user) );
    }

    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
        log.warn("自定义用户名密码身份认证过滤器 登录失败处理器开始");
        // 判断如果是这种异常, 那么就是用户名或密码错误
        if( failed instanceof InternalAuthenticationServiceException ){
            responseWrite(response, ResponseMessage.error("该用户不存在"));
        }else{
            // AuthenticationException 内置了很多的错误信息提示 org.springframework.security.messages(core核心包下message)
            responseWrite(response, ResponseMessage.error(failed.getMessage()));
        }

    }

    /** 方法抽取: 相应数据给前端 **/
    private void responseWrite(HttpServletResponse response, ResponseMessage message) throws IOException {
        // 手动添加跨域响应头
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setContentType("application/json;charset=utf-8");
        response.setCharacterEncoding("utf-8");
        response.getOutputStream().write(objectMapper.writeValueAsString(message).getBytes());
    }

    /** 必须, 否则会报错 **/
    @Autowired
    @Override
    public void setAuthenticationManager(AuthenticationManager authenticationManager) {
        super.setAuthenticationManager(authenticationManager);
    }
}
